/**
 *    @file       servertask.cpp
 *
 *    @brief      
 *    @details
 *
 *    @version    1.0
 *    @date       02/19/2014 09:37:27 PM
 *
 *    @author     Theophilus (), wangtf418@gmail.com 
 */
#include <errno.h>
#include "servertask.h"
#include "server.h"
#include "netprocessthread.h"

servertask::servertask(csocket *sock, netprocessthread *netthread, const comargs *args /* = NULL */)
	: sockettask(sock, netthread, args), m_read_state(READ_HEAD), m_cur_recvlen(0), m_close_flag(false)
{

}

servertask::~servertask()
{

}

bf_int_t servertask::init(bf_time_t timeout /*  = SOCKTASK_TIMEOUT */, bf_int_t sock_buflen /*  = 102400 */)
{
	reset_buf();
	return sockettask::init();
}

bf_int_t servertask::proc_msg(message *msg)
{
	bufmsgbody *body = (bufmsgbody*)msg->get_msgbody();
	if (body)
	{
		put_send_packet(body->get_buf(), body->get_buflen());
		body->detach_buf();
	}
	return BF_OK;
}

bf_int_t servertask::process_io_event(bf_int_t events)
{
	if ((events & BF_EPOLL_ERR) || (events & BF_EPOLL_HUP))
	{
		destroy();
		return BF_ERROR;
	}

	m_last_activetime = server::get()->get_time();

	bf_int_t ret = BF_OK;
	if (events & BF_EPOLL_IN)
	{
		ret = recv_process();
		if (ret == BF_ERROR)
		{
			destroy();
			return BF_ERROR;
		}
	}

	if (events & BF_EPOLL_OUT)
	{
		ret = send_process();
		if (ret == BF_ERROR)
		{
			destroy();
			return BF_ERROR;
		}
	}

	if (m_close_flag && ret == BF_SUCC)
	{
		destroy();
	}

	return BF_OK;
}

bf_int_t servertask::recv_process()
{
	bf_int_t ret = BF_OK;	
	
	switch (m_read_state)
	{
		case READ_HEAD:
			{
				ret = read_head();
				break;
			}
		case READ_BODY:
			{
				ret = read_body();
				break;
			}
	}

	if (ret == BF_SUCC) //recv suc
	{
		process_recv_packet(m_recvbuf, m_cur_recvlen);
		reset_buf();
	}

	return BF_OK;
}

bf_int_t servertask::send_process()
{
	if (!m_cur_sendmsg)	
	{
		if (m_send_list.begin() != m_send_list.end())
		{
			m_cur_sendmsg = m_send_list.front();
			m_send_list.pop_front();
		}
		else
		{
			modify_epoll(BF_EPOLL_IN);
			return BF_OK;
		}
	}

	bf_int_t ret = send_packet(m_cur_sendmsg);
	if (ret == BF_SUCC)
	{
		delete m_cur_sendmsg;
		m_cur_sendmsg = NULL;

		if (m_send_list.begin() == m_send_list.end())
		{
			modify_epoll(BF_EPOLL_IN);
			return BF_SUCC;
		}
		else
		{
			m_cur_sendmsg = m_send_list.front();
			m_send_list.pop_front();
			return BF_OK;
		}
	}
	else
	{
		return ret;
	}
}

bf_int_t servertask::read_head()
{
	bf_int_t need_read = m_headlen - m_cur_recvlen;
	bf_int_t readedlen = m_socket->recv(m_recvbuf, need_read, MSG_DONTWAIT);

	if (readedlen == 0)
	{
		return BF_ERROR;	//client close
	}
	else if (readedlen < 0)
	{
		if (errno != EINTR && errno != EAGAIN)
		{
			return BF_ERROR;
		}
		return BF_OK;
	}

	m_cur_recvlen += readedlen;
	if (readedlen == need_read)
	{
		m_bodylen = get_bodylen(m_recvbuf, m_headlen);
		if (m_headlen + m_bodylen > TCP_RECV_BUF_LEN)
		{
			return BF_ERROR;
		}

		if (m_bodylen > 0)
		{
			m_read_state = READ_BODY;
			return BF_OK;
		}
		else
		{
			return BF_SUCC;
		}
	}

	return BF_OK;
}

bf_int_t servertask::read_body()
{
	bf_int_t need_read = m_headlen + m_bodylen - m_cur_recvlen;
	bf_int_t readedlen = m_socket->recv(m_recvbuf + m_cur_recvlen, need_read, MSG_DONTWAIT);

	if (readedlen == 0)
	{
		return BF_ERROR;	//client close
	}
	else if (readedlen < 0)
	{
		if (errno != EINTR && errno != EAGAIN)
		{
			return BF_ERROR;
		}
		return BF_OK;
	}

	m_cur_recvlen += readedlen;
	if (readedlen == need_read)
	{
		return BF_SUCC;
	}

	return BF_OK;
}

bf_int_t servertask::process_recv_packet(bf_char_t *buf, bf_size_t buflen)
{
	bf_char_t *newbuf = new bf_char_t[buflen];
	memcpy(newbuf, buf, buflen);
	addr_bufmsgbody *body = new addr_bufmsgbody(newbuf, buflen, m_socket->get_sockaddr());

	m_netthread->send_msg(THD_TYPE_PROCESS, RAND_THD_INDEX, 0, MSG_TYPE_PROC, body, m_taskid);
	return BF_OK;
}

bf_int_t servertask::send_packet(send_message *cur_sendmsg)
{
	bf_size_t cur_sendlen = cur_sendmsg->get_cur_sendlen();
	bf_size_t buf_len = cur_sendmsg->get_buflen();
	bf_size_t sendlen = (TCP_SEND_LEN_MAX > (buf_len - cur_sendlen))? (buf_len - cur_sendlen):TCP_SEND_LEN_MAX;

	bf_int_t sendedlen = m_socket->send(cur_sendmsg->get_buf() + cur_sendlen, sendlen, MSG_DONTWAIT);
	if (sendedlen >= 0)
	{
		cur_sendlen += sendedlen;
		cur_sendmsg->set_cur_sendlen(cur_sendlen);
		if (cur_sendlen == buf_len)
		{
			return BF_SUCC;
		}
		else
		{
			return BF_OK;
		}
	}
	else
	{
		return BF_ERROR;
	}
}



